home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AOL File Library: 2,801 to 2,900
/
aol-file-protocol-4400-2801-to-2900.zip
/
AOLDLs
/
C++ Files Library
/
C++ Spline Class V 1.02
/
C++ Spline Class 1.02.sea
/
Spline Class
/
2DSpline.cp
next >
Wrap
Text File
|
1993-10-01
|
48KB
|
1,244 lines
/************************************************************************************************/
/* Chris Marshall */
/* */
/* Nikon Electronic Imaging Dept */
/* 1300 Walt Whitman Road */
/* Melville, NY 11747 */
/* (516) 547-4200 */
/* */
/************************************************************************************************/
/* File Name: 2DSpline.cp */
/* Description: Implementation file for a 2-dimensional B-spline class */
/* Primary Author: Chris Marshall - from algorithm modified by Tom Knoll & Khouri Giordano */
/* Version: 1.02 */
/* Project: Library file */
/* Compiler(s): Symantec C++ 6.0 */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/* 09/30/93 Chris Marshall I fixed a little bug in the coefficient calculator that made */
/* the curve just the teensiest bit WRONG. */
/* 10/01/93 Chris Marshall I fixed another little bug in the coefficient calculator that */
/* made the curve just the teensiest bit WRONG (floating point). */
/* */
/************************************************************************************************/
/* This class implements a basic B-spline (the kind that passes a curve through points, as */
/* opposed to around them). Tom Knoll added the little hack for eliminating the need for */
/* points beyond the endpoints, Khouri did a port from Pascal, and I made it work for multiple */
/* dynamic points, and made it classy. */
/* Basically, it's a plain old spline, wrapped in a C++ class. Since it's a limited spline */
/* algorithm, made almost exclusively for gamma table manipulation, I've taken the opprtunity */
/* to force the points to be added (and internally stored) into long integer form. In most */
/* cases, this will not result in a loss of accuracy, and it makes the class much faster. If */
/* this class is used in a non-FPU machine, it may be a wee bit on the sluggish side, so I */
/* suggest limiting the scope and number of data points in these cases. This class will track */
/* a single, "selected" point, and has special methods for dealing with this point as a default */
/* destination for operations. Data points are stored in ascending X-axis order. The two */
/* endpoints are considered to be the outside boundaries of the spline, and all xValues that */
/* are presented beyond the endpoints will be returned the endpoint's yValue. */
/* There is a subclass, called "FixedSpline", that does all the calculations in fixed-point. */
/* It is quite optimized for speed, and will perform quite well. Don't expect the same degree */
/* of accuracy from it, but for most cases (gamma table manipulation), this won't make any real */
/* difference. It'll get you something, but its not a screamer if you have a sluggish machine. */
/* These classes could also be very useful for things like waveform and envelope manipulation. */
/************************************************************************************************/
#include "2DSpline.h"
/************************************************************************************************/
/* Function Name: Spline */
/* Description: Initializes the object, and sets two locked endpoints */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
Spline::Spline ( long x0, long y0, long x1, long y1, long hitRadius )
{
this->Initialize ( );
this->AddSplinePoint ( x0, y0 );
this->AddSplinePoint ( x1, y1 );
fHitRadius = hitRadius;
}
/************************************************************************************************/
/* Function Name: CreateSplineCoefficients */
/* Description: Calculates a table of spline coefficients for caculating a spline curve */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/* 09/30/93 Chris Marshall I fixed a little bug in the coefficient calculator that made */
/* the curve just the teensiest bit WRONG. */
/* 10/01/93 Chris Marshall I fixed another little bug in the coefficient calculator that */
/* made the curve just the teensiest bit WRONG. */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
void Spline::CreateCoefficients ( )
{
register short count;
register long double lastSlope, slope, temp;
long lastDeltaX, deltaX;
long size = (long)sizeof ( long double ) * (long)fNumPoints;
if ( !size )
return;
fNumPoints--; // "Neck down" our point count by one
lastDeltaX = *(*fXArray + 1) - **fXArray;
**fSlopeArray = lastSlope = (long double)(*(*fYArray + 1) - **fYArray)
/ (long double)lastDeltaX;
for ( count = 2; count <= fNumPoints; ++count )
{
deltaX = *(*fXArray + count) - *(*fXArray + (count - 1));
slope = (long double)(*(*fYArray + count) - *(*fYArray + (count - 1)))
/ (long double)deltaX;
*(*fSlopeArray + (count - 1)) = ((lastSlope * (long double)deltaX) + (slope
* (long double)lastDeltaX)) / (long double)(lastDeltaX + deltaX);
lastDeltaX = deltaX;
lastSlope = slope;
}
*(*fSlopeArray + fNumPoints) = (2 * lastSlope) - *(*fSlopeArray + (fNumPoints - 1));
**fSlopeArray = (2 * **fSlopeArray) - *(*fSlopeArray + 1);
if ( fNumPoints > 2 ) // If we have more than three points, we invent endpoint derivatives
{
**fPAl2 = *(*fPAl1 + fNumPoints) = 0.5;
**fPAl3 = 0.75 * (**fSlopeArray + *(*fSlopeArray + 1));
*(*fPAl3 + fNumPoints) = 0.75 * (*(*fSlopeArray + (fNumPoints - 1))
+ *(*fSlopeArray + fNumPoints));
for ( count = 1; count <= fNumPoints; ++count) // Fixed an under count problem here
{
if ( count < fNumPoints )
{
temp = (long double)(*(*fXArray + (count + 1)) - *(*fXArray + (count - 1))) * 2.0;
*(*fPAl1 + count) = (long double)(*(*fXArray + (count + 1)) - *(*fXArray + count))
/ temp;
// A shortcut didn't work, so this is back
*(*fPAl2 + count) = (long double)(*(*fXArray + count) - *(*fXArray + (count - 1)))
/ temp;
*(*fPAl3 + count) = 1.5 * *(*fSlopeArray + count);
}
temp = (1 - (*(*fPAl2 + (count - 1)) * *(*fPAl1 + count)));
if ( count < fNumPoints )
*(*fPAl2 + count) = *(*fPAl2 + count) / temp;
*(*fPAl3 + count) = (*(*fPAl3 + count) - *(*fPAl3 + (count - 1)) * *(*fPAl1 + count))
/ temp;
}
for ( count = fNumPoints - 1; count >= 0; --count )
*(*fSlopeArray + count) = *(*fPAl3 + count) - (*(*fPAl2 + count)
* *(*fPAl3 + (count + 1)));
*(*fSlopeArray + fNumPoints) = *(*fPAl3 + fNumPoints);
}
fNumPoints++;
}
/************************************************************************************************/
/* Function Name: Initialize */
/* Description: Initializes the class' variables */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
void Spline::Initialize ( )
{
fNumPoints = 0;
fXArray = 0L;
fYArray = 0L;
fSlopeArray = 0L;
fHitRadius = 0;
fSelectedPoint = 0;
fPAl1 = fPAl2 = fPAl3 = 0L;
fAlloc = 0;
}
/************************************************************************************************/
/* Function Name: ~Spline */
/* Description: Deallocates the arrays upon destruction of the object */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
Spline::~Spline ( )
{
if ( fXArray )
DisposHandle ( (Handle)fXArray );
if ( fYArray )
DisposHandle ( (Handle)fYArray );
if ( fSlopeArray )
DisposHandle ( (Handle)fSlopeArray );
if ( fPAl3 )
DisposHandle ( (Handle)fPAl3 );
if ( fPAl2 )
DisposHandle ( (Handle)fPAl2 );
if ( fPAl1 )
DisposHandle ( (Handle)fPAl1 );
}
/************************************************************************************************/
/* Function Name: AddSplinePoint */
/* Description: Adds a point to the list of points, and recalculates the coefficients */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
short Spline::AddSplinePoint ( long xValue, long yValue )
{
short index = 0;
long size = (fNumPoints + 1) * sizeof ( long );
long sizeS = (fNumPoints + 1) * sizeof ( long double );
if ( fNumPoints )
{
if ( !(index = this->IsASplinePoint ( xValue, yValue, true )) )
{
while ( (index < fNumPoints) && (xValue > *(*fXArray + index)) ) index++;
if ( (index == fNumPoints) || (xValue != *(*fXArray + index)) )
{
SetHandleSize ( (Handle)fXArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fYArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fSlopeArray, sizeS );
if ( MemError ( ) == noErr )
{
size = (fNumPoints - index) * sizeof ( long );
sizeS = (fNumPoints - index) * sizeof ( long double );
if ( size )
{
BlockMove ( (*fXArray + index), (*fXArray + 1 + index), size );
BlockMove ( (*fYArray + index), (*fYArray + 1 + index), size );
BlockMove ( (*fSlopeArray + index), (*fSlopeArray + 1 + index), sizeS );
}
*(*fXArray + index) = xValue;
*(*fYArray + index) = yValue;
fNumPoints++;
fSelectedPoint = index + 1;
// We need to add another block to our working buffers
if ( (fNumPoints > fAlloc) && fPAl1 && fPAl2 && fPAl3 )
{
fAlloc += kInc;
sizeS = fAlloc * sizeof ( long double );
SetHandleSize ( (Handle)fPAl1, sizeS );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fPAl2, sizeS );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fPAl3, sizeS );
}
this->CreateCoefficients ( );
}
else
index = -1;
}
else
{
fSelectedPoint = index + 1;
*(*fYArray + index) = yValue;
}
}
else
fSelectedPoint = index + 1;
}
else
{
fXArray = (long**) NewHandle ( size );
if ( fXArray )
{
fYArray = (long**) NewHandle ( size );
if ( fYArray )
{
fSlopeArray = (long double**) NewHandle ( sizeS );
if ( fSlopeArray )
{
fPAl1 = (long double**)NewHandle ( kInc * sizeof ( long double ) );
if ( fPAl1 )
{
fPAl2 = (long double**)NewHandle ( kInc * sizeof ( long double ) );
if ( fPAl2 )
{
fPAl3 = (long double**)NewHandle ( kInc * sizeof ( long double ) );
if ( fPAl3 )
{
fAlloc = kInc;
**fXArray = xValue;
**fYArray = yValue;
fNumPoints = 1;
fSelectedPoint = 1;
}
else
{
DisposHandle ( (Handle)fPAl2 );
fPAl2 = 0L;
DisposHandle ( (Handle)fPAl1 );
fPAl1 = 0L;
DisposHandle ( (Handle)fSlopeArray );
fSlopeArray = 0L;
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fPAl1 );
fPAl1 = 0L;
DisposHandle ( (Handle)fSlopeArray );
fSlopeArray = 0L;
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fSlopeArray );
fSlopeArray = 0L;
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
index = -1;
}
}
else
index = -1;
}
return index + 1;
}
/************************************************************************************************/
/* Function Name: PointIsOnLine */
/* Description: Tests the given point to see if it's on the line */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
/* radius is a "fuzzy area" that allows the point to be around the line, but not exactly on it. */
/* If radius is nonzero, then it describes a radius around the given point. This is useful for */
/* hit testing mouse coordinates in something like a gamma table. */
/************************************************************************************************/
Boolean Spline::PointIsOnLine ( long & xValue, long & yValue )
{
Boolean isOn = false;
long yVal = this->GetYValue ( xValue );
if ( (yVal <= (yValue + fHitRadius)) && (yVal >= (yValue - fHitRadius)) )
isOn = true;
else
{
yVal = this->GetYValue ( xValue - fHitRadius );
if ( (yVal <= (yValue + fHitRadius)) && (yVal >= (yValue - fHitRadius)) )
{
xValue = xValue - fHitRadius;
isOn = true;
}
else
{
yVal = this->GetYValue ( xValue + fHitRadius );
if ( (yVal <= (yValue + fHitRadius)) && (yVal >= (yValue - fHitRadius)) )
{
xValue = xValue + fHitRadius;
isOn = true;
}
}
}
if ( isOn )
yValue = yVal;
return isOn;
}
/************************************************************************************************/
/* Function Name: IsASplinePoint */
/* Description: Tests the given point to see if it's on the line */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
/* fHitRadius is a "fuzzy area" that lets the point be around the point, but not right on it. */
/* If it is nonzero, then it describes a radius around the given point. This is useful for hit */
/* testing mouse coordinates in something like a gamma table. xOnly is a flag that the caller */
/* sets if they just want to find out if the horizontal coordinate matches, but without */
/* checking the vertical coordinate. */
/************************************************************************************************/
short Spline::IsASplinePoint ( long & xValue, long & yValue, Boolean xOnly )
{
short ret = 0;
if ( fNumPoints )
{
for ( short index = 0; index < fNumPoints; index++ )
{
if ( (xValue >= *(*fXArray + index) - fHitRadius)
&& (xValue <= *(*fXArray + index) + fHitRadius) )
{
xValue = *(*fXArray + index);
if ( !xOnly ) // Have to be anal-retentive, and check the Y
{
if ( (yValue >= *(*fYArray + index) - fHitRadius)
&& (yValue <= *(*fYArray + index) + fHitRadius) )
{
yValue = *(*fYArray + index);
ret = index + 1;
break;
}
else // Yeah, I know, it's real gross, but it's reasonably fast
if ( (yValue >= *(*fYArray + index) - (fHitRadius >> 1))
&& (yValue <= *(*fYArray + index) + (fHitRadius >> 1)) )
{
yValue = *(*fYArray + index);
ret = index + 1;
break;
}
}
else // We're satisfied with just the X matching up
{
yValue = *(*fYArray + index);
ret = index + 1;
break;
}
}
}
}
return ret;
}
/************************************************************************************************/
/* Function Name: PointIsBetween */
/* Description: Returns indexes of the spline points above and below the given point */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
/* boundary will tell you if the tested point is equal to one or the other points it is between */
/* on the x-axis. boundary will be -1 if it is the point returned in below, 1 if it is the */
/* point returned in above, and 0 if it is not equal to either. */
/************************************************************************************************/
short Spline::PointIsBetween ( long xValue, short & above, short & below )
{
short boundary = 0;
register short index = 0;
below = -1;
above = -1;
while ( (index < fNumPoints) && (xValue > (*(*fXArray + index) - fHitRadius)) ) index++;
if ( index < fNumPoints )
{
if ( xValue == *(*fXArray + index) )
boundary = -1;
if ( xValue >= *(*fXArray + index) )
below = index + 1;
}
for ( index = fNumPoints; index-- && (xValue < *(*fXArray + index)); )
{ /* So the $#@!! compiler doesn't give us a warning! */ };
if ( index >= 0 )
{
if ( xValue == *(*fXArray + index) )
boundary = 1;
if ( xValue <= *(*fXArray + index) )
above = index + 1;
}
return boundary; // Return a value indicating that the value is equal to one of the points
}
/************************************************************************************************/
/* Function Name: GetSplinePoint */
/* Description: Returns the coordinates of an indexed spline point */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
short Spline::GetSplinePoint ( short index, long & xValue, long & yValue )
{
if ( index && (index <= fNumPoints) )
{
xValue = *(*fXArray + (index - 1));
yValue = *(*fYArray + (index - 1));
}
else
{
xValue = -1;
yValue = -1;
}
return index;
}
/************************************************************************************************/
/* Function Name: DeleteSplinePoint */
/* Description: Takes a spline point out of the list */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
void Spline::DeleteSplinePoint ( short index )
{
if ( index && (index <= fNumPoints) )
{
long size = (fNumPoints - index) * sizeof ( long );
long sizeS = (fNumPoints - index) * sizeof ( long double );
if ( size )
{
BlockMove ( (*fXArray + index), (*fXArray + (index - 1)), size );
BlockMove ( (*fYArray + index), (*fYArray + (index - 1)), size );
BlockMove ( (*fSlopeArray + index), (*fSlopeArray + (index - 1)), sizeS );
}
size = --fNumPoints * sizeof ( long );
sizeS = fNumPoints * sizeof ( long double );
if ( size )
{
SetHandleSize ( (Handle)fXArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fYArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fSlopeArray, sizeS );
if ( MemError ( ) == noErr )
this->CreateCoefficients ( );
}
else
{
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
DisposHandle ( (Handle)fSlopeArray );
fSlopeArray = 0L;
DisposHandle ( (Handle)fPAl3 );
fPAl3 = 0L;
DisposHandle ( (Handle)fPAl2 );
fPAl2 = 0L;
DisposHandle ( (Handle)fPAl1 );
fPAl1 = 0L;
}
if ( fSelectedPoint > index )
fSelectedPoint--;
else
if ( (fSelectedPoint == index) && (index > 2) )
fSelectedPoint = index - 1;
}
}
/************************************************************************************************/
/* Function Name: ChangeSplinePoint */
/* Description: Alters the value of a spline point, replacing it if necessary */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
void Spline::ChangeSplinePoint ( short & index, long xValue, long yValue )
{
register short count;
long domainL, domainH;
if ( index > 1 )
domainL = *(*fXArray + (index - 2));
else
domainL = xValue - 1;
if ( index < fNumPoints )
domainH = *(*fXArray + index);
else
domainH = xValue + 1;
fSelectedPoint = index;
if ( (xValue > domainL) && (xValue < domainH) )
{
*(*fXArray + (index - 1)) = xValue;
*(*fYArray + (index - 1)) = yValue;
this->CreateCoefficients ( );
}
else
if ( !this->IsASplinePoint ( xValue, yValue, true ) )
{
this->DeleteSplinePoint ( index );
index = this->AddSplinePoint ( xValue, yValue );
}
}
/************************************************************************************************/
/* Function Name: GetYValue */
/* Description: Returns a Y value along a spline curve described by coefficients */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
long Spline::GetYValue ( long xValue )
{
register short count = 1;
register long double loPerc, hiPerc;
register long ret = 0L, deltaX;
if ( !fNumPoints )
return 0;
if ( xValue < **fXArray )
return ( **fYArray );
if ( xValue > *(*fXArray + (fNumPoints - 1)) )
return ( *(*fYArray + (fNumPoints - 1)) );
if ( fNumPoints > 2 )
{
while ( (count < fNumPoints) && (xValue > *(*fXArray + count)) ) count++;
deltaX = *(*fXArray + count) - *(*fXArray + (count - 1));
loPerc = (long double)(xValue - *(*fXArray + (count - 1))) / (long double)deltaX;
hiPerc = (long double)(*(*fXArray + count) - xValue) / (long double)deltaX;
ret = (long)(*(*fYArray + (count - 1)) * (2.0 - hiPerc + loPerc) + *(*fSlopeArray
+ (count - 1)) * (long double)deltaX * loPerc) * hiPerc * hiPerc
+ (*(*fYArray + count) * (2.0 - loPerc + hiPerc) - *(*fSlopeArray + count)
* (long double)deltaX * hiPerc) * loPerc * loPerc;
}
else // Fast straight line if we only have two points
if ( fNumPoints == 2 )
ret = ((((xValue - **fXArray) * (*(*fYArray + 1) - **fYArray))
/ (*(*fXArray + 1) - **fXArray)) + **fYArray);
else
if ( fNumPoints == 1 )
ret = **fYArray;
return ret;
}
/************************************************************************************************/
/* Function Name: GetRealYValue */
/* Description: Returns a Y value as a real number (slower, but more accurate) */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
long double Spline::GetRealYValue ( long double xValue )
{
register short count = 1;
register long double loPerc, hiPerc, ret = 0L, deltaX;
if ( !fNumPoints )
return 0;
if ( xValue < (long double)**fXArray )
ret = (long double)**fYArray;
else
{
if ( xValue > (long double)*(*fXArray + (fNumPoints - 1)) )
ret = (long double)*(*fYArray + (fNumPoints - 1));
else
if ( fNumPoints > 2 )
{
while ( (count < fNumPoints) && (xValue > *(*fXArray + count)) ) count++;
deltaX = (long double)*(*fXArray + count) - *(*fXArray + (count - 1));
loPerc = (xValue - (long double)*(*fXArray + (count - 1))) / deltaX;
hiPerc = ((long double)*(*fXArray + count) - xValue) / deltaX;
ret = (*(*fYArray + (count - 1)) * (2.0 - hiPerc + loPerc) + *(*fSlopeArray
+ (count - 1)) * deltaX * loPerc) * hiPerc * hiPerc
+ (*(*fYArray + count) * (2.0 - loPerc + hiPerc) - *(*fSlopeArray + count)
* deltaX * hiPerc) * loPerc * loPerc;
}
else // Fast straight line if we only have two points
if ( fNumPoints == 2 )
ret = ((((xValue - **fXArray) * (*(*fYArray + 1) - **fYArray))
/ (*(*fXArray + 1) - **fXArray)) + **fYArray);
else
if ( fNumPoints == 1 )
ret = (long double)**fYArray;
}
return ret;
}
/************************************************************************************************/
/* Function Name: FixedSpline */
/* Description: Initializes the object, and sets two locked endpoints */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
FixedSpline::FixedSpline ( long x0, long y0, long x1, long y1, long hitRadius )
{
this->Initialize ( );
this->AddSplinePoint ( x0, y0 );
this->AddSplinePoint ( x1, y1 );
fHitRadius = hitRadius;
}
/************************************************************************************************/
/* Function Name: CreateSplineCoefficients */
/* Description: Calculates a table of spline coefficients for caculating a spline curve */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/* 09/30/93 Chris Marshall I fixed a little bug in the coefficient calculator that made */
/* the curve just the teensiest bit WRONG. */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
void FixedSpline::CreateCoefficients ( )
{
register short count;
register Fixed lastSlope, slope, lastDeltaX, deltaX, work;
if ( !fNumPoints )
return;
fNumPoints--; // "Neck down" our point count by one
lastDeltaX = (*(*fXArray + 1) - **fXArray) << 16;
**fFixedArray = lastSlope = FixDiv ( (*(*fYArray + 1) - **fYArray) << 16, lastDeltaX );
for ( count = 2; count <= fNumPoints; ++count )
{
deltaX = (*(*fXArray + count) - *(*fXArray + (count - 1))) << 16;
slope = FixDiv ( (*(*fYArray + count) - *(*fYArray + (count - 1))) << 16, deltaX );
*(*fFixedArray + (count - 1)) = FixDiv ( FixMul ( lastSlope, deltaX )
+ FixMul ( slope, lastDeltaX ),
(lastDeltaX + deltaX) );
lastDeltaX = deltaX;
lastSlope = slope;
}
*(*fFixedArray + fNumPoints) = (lastSlope << 1) - *(*fFixedArray + (fNumPoints - 1));
**fFixedArray = (**fFixedArray << 1) - *(*fFixedArray + 1);
if ( fNumPoints > 2 ) // If we have more than three points, we invent endpoint derivatives
{
**fPAf2 = *(*fPAf1 + fNumPoints) = 0x00008000;
**fPAf3 = FixMul ( 0x0000C000, (**fFixedArray + *(*fFixedArray + 1)) );
*(*fPAf3 + fNumPoints) = FixMul ( 0x0000C000, (*(*fFixedArray + (fNumPoints - 1))
+ *(*fFixedArray + fNumPoints)) );
for ( count = 1; count <= fNumPoints; ++count)
{
if ( count < fNumPoints )
{
work = (*(*fXArray + (count + 1)) - *(*fXArray + (count - 1))) << 17;
*(*fPAf1 + count) = FixDiv ( (*(*fXArray + (count + 1)) - *(*fXArray + count)) << 16,
work );
// Okay, I tried this code is back
*(*fPAf2 + count) = FixDiv ( (*(*fXArray + count) - *(*fXArray + (count - 1))) << 16,
work );
*(*fPAf3 + count) = *(*fFixedArray + count) + (*(*fFixedArray + count) >> 1);
}
work = 0x00010000 - FixMul ( *(*fPAf2 + (count - 1)), *(*fPAf1 + count) );
if ( count < fNumPoints )
*(*fPAf2 + count) = FixDiv ( *(*fPAf2 + count), work );
*(*fPAf3 + count) = FixDiv ( *(*fPAf3 + count)
- FixMul ( *(*fPAf3 + (count - 1)), *(*fPAf1 + count) ), work );
}
for ( count = fNumPoints - 1; count >= 0; count-- )
*(*fFixedArray + count) = *(*fPAf3 + count) - FixMul ( *(*fPAf2 + count),
*(*fPAf3 + (count + 1)) );
*(*fFixedArray + fNumPoints) = *(*fPAf3 + fNumPoints);
}
fNumPoints++;
}
/************************************************************************************************/
/* Function Name: Initialize */
/* Description: Initializes the class' variables */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
void FixedSpline::Initialize ( )
{
fFixedArray = 0L;
fPAf1 = fPAf2 = fPAf3 = 0L;
}
/************************************************************************************************/
/* Function Name: ~FixedSpline */
/* Description: Deallocates the array upon destruction of the object */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
FixedSpline::~FixedSpline ( )
{
if ( fFixedArray )
DisposHandle ( (Handle)fFixedArray );
if ( fPAf3 )
DisposHandle ( (Handle)fPAf3 );
if ( fPAf2 )
DisposHandle ( (Handle)fPAf2 );
if ( fPAf1 )
DisposHandle ( (Handle)fPAf1 );
if ( fXArray )
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
if ( fYArray )
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
}
/************************************************************************************************/
/* Function Name: AddSplinePoint */
/* Description: Adds a point to the list of points, and recalculates the coefficients */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
short FixedSpline::AddSplinePoint ( long xValue, long yValue )
{
short index = 0;
long size = (fNumPoints + 1) * sizeof ( long );
long sizeS = (fNumPoints + 1) * sizeof ( Fixed );
if ( fNumPoints )
{
if ( !(index = this->IsASplinePoint ( xValue, yValue, true )) )
{
while ( (index < fNumPoints) && (xValue > *(*fXArray + index)) ) index++;
if ( (index == fNumPoints) || (xValue != *(*fXArray + index)) )
{
SetHandleSize ( (Handle)fXArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fYArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fFixedArray, sizeS );
if ( MemError ( ) == noErr )
{
size = (fNumPoints - index) * sizeof ( long );
sizeS = (fNumPoints - index) * sizeof ( Fixed );
if ( size )
{
BlockMove ( (*fXArray + index), (*fXArray + 1 + index), size );
BlockMove ( (*fYArray + index), (*fYArray + 1 + index), size );
BlockMove ( (*fFixedArray + index), (*fFixedArray + 1 + index), sizeS );
}
*(*fXArray + index) = xValue;
*(*fYArray + index) = yValue;
fNumPoints++;
fSelectedPoint = index + 1;
// We need to add another block to our working buffers
if ( (fNumPoints > fAlloc) && fPAf1 && fPAf2 && fPAf3 )
{
fAlloc += kInc;
sizeS = fAlloc * sizeof ( Fixed );
SetHandleSize ( (Handle)fPAf1, sizeS );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fPAf2, sizeS );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fPAf3, sizeS );
}
this->CreateCoefficients ( );
}
else
index = -1;
}
else
{
fSelectedPoint = index + 1;
*(*fYArray + index) = yValue;
}
}
else
fSelectedPoint = index + 1;
}
else
{
fXArray = (long**) NewHandle ( size );
if ( fXArray )
{
fYArray = (long**) NewHandle ( size );
if ( fYArray )
{
fFixedArray = (Fixed**) NewHandle ( sizeS );
if ( fFixedArray )
{
fPAf1 = (Fixed**)NewHandle ( kInc * sizeof ( Fixed ) );
if ( fPAf1 )
{
fPAf2 = (Fixed**)NewHandle ( kInc * sizeof ( Fixed ) );
if ( fPAf2 )
{
fPAf3 = (Fixed**)NewHandle ( kInc * sizeof ( Fixed ) );
if ( fPAf3 )
{
fAlloc = kInc;
**fXArray = xValue;
**fYArray = yValue;
fNumPoints = 1;
fSelectedPoint = 1;
}
else
{
DisposHandle ( (Handle)fPAf2 );
fPAf2 = 0L;
DisposHandle ( (Handle)fPAf1 );
fPAf1 = 0L;
DisposHandle ( (Handle)fFixedArray );
fFixedArray = 0L;
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fPAf1 );
fPAf1 = 0L;
DisposHandle ( (Handle)fFixedArray );
fFixedArray = 0L;
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fFixedArray );
fFixedArray = 0L;
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
index = -1;
}
}
else
{
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
index = -1;
}
}
else
index = -1;
}
return index + 1;
}
/************************************************************************************************/
/* Function Name: DeleteSplinePoint */
/* Description: Takes a spline point out of the list */
/* Primary Author: Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
void FixedSpline::DeleteSplinePoint ( short index )
{
if ( index && (index <= fNumPoints) )
{
long size = (fNumPoints - index) * sizeof ( long );
long sizeS = (fNumPoints - index) * sizeof ( Fixed );
if ( size )
{
BlockMove ( (*fXArray + index), (*fXArray + (index - 1)), size );
BlockMove ( (*fYArray + index), (*fYArray + (index - 1)), size );
BlockMove ( (*fFixedArray + index), (*fFixedArray + (index - 1)), sizeS );
}
size = --fNumPoints * sizeof ( long );
sizeS = fNumPoints * sizeof ( Fixed );
if ( size )
{
SetHandleSize ( (Handle)fXArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fYArray, size );
if ( MemError ( ) == noErr )
SetHandleSize ( (Handle)fFixedArray, sizeS );
if ( MemError ( ) == noErr )
this->CreateCoefficients ( );
}
else
{
DisposHandle ( (Handle)fXArray );
fXArray = 0L;
DisposHandle ( (Handle)fYArray );
fYArray = 0L;
DisposHandle ( (Handle)fFixedArray );
fFixedArray = 0L;
DisposHandle ( (Handle)fPAf3 );
fPAf3 = 0L;
DisposHandle ( (Handle)fPAf2 );
fPAf2 = 0L;
DisposHandle ( (Handle)fPAf1 );
fPAf1 = 0L;
}
if ( fSelectedPoint > index )
fSelectedPoint--;
else
if ( (fSelectedPoint == index) && (index > 2) )
fSelectedPoint = index - 1;
}
}
/************************************************************************************************/
/* Function Name: GetFixYValue */
/* Description: Returns a Y value along a spline curve described by coefficients */
/* Primary Author: Tom Knoll, Khouri Giordano & Chris Marshall */
/************************************************************************************************/
/* MODIFICATION HISTORY */
/************************************************************************************************/
/* Date Author Description */
/* */
/************************************************************************************************/
/*##############################################################################################*/
/************************************************************************************************/
Fixed FixedSpline::GetFixYValue ( Fixed xValue )
{
register short count = 1;
register Fixed loPerc, hiPerc, deltaX, x1, x_1, y1, y_1;
Fixed ret;
register long xComp = Fix2Long ( xValue );
if ( !fNumPoints )
return 0;
if ( (xComp < **fXArray) || (fNumPoints == 1) )
return **fYArray << 16;
if ( xComp > *(*fXArray + (fNumPoints - 1)) )
return *(*fYArray + (fNumPoints - 1)) << 16;
while ( (count < fNumPoints) && (xComp > *(*fXArray + count)) ) count++;
x1 = *(*fXArray + count) << 16;
x_1 = *(*fXArray + (count - 1)) << 16;
deltaX = x1 - x_1;
loPerc = FixDiv ( xValue - x_1, deltaX );
hiPerc = FixDiv ( x1 - xValue, deltaX );
if ( fNumPoints == 2 ) // Fast straight line for 2 points
ret = ((((xComp - **fXArray) * (*(*fYArray + 1) - **fYArray))
/ (*(*fXArray + 1) - **fXArray)) + **fYArray) << 16;
else
// Don't even try to decipher this line of spaghetti!
ret = FixMul ( FixMul ( *(*fYArray + (count - 1)) << 16, (0x00020000 - hiPerc + loPerc) )
+ FixMul ( *(*fFixedArray + (count - 1)), FixMul ( deltaX, loPerc ) ),
FixMul ( hiPerc, hiPerc ) ) + FixMul ( FixMul ( *(*fYArray + count) << 16,
(0x00020000 - loPerc + hiPerc) ) - FixMul ( *(*fFixedArray + count),
FixMul ( deltaX, hiPerc ) ), FixMul ( loPerc, loPerc ) );
return ret;
}
/************************************************************************************************/